package com.road.shiro;

import java.util.List;

import org.apache.commons.lang3.StringUtils;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.SimpleAuthenticationInfo;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;

import com.road.model.entity.Resource;
import com.road.model.entity.Role;
import com.road.model.entity.User;
import com.road.service.ResourceService;
import com.road.service.RoleService;
import com.road.service.UserService;

/**
 * shiro权限认证
 * 
 * @author jackson.zhang
 *
 */
public class ShiroDbRealm extends AuthorizingRealm {

	private static Logger LOGGER = LoggerFactory.getLogger(ShiroDbRealm.class);

	@Autowired
	private UserService userService;
	@Autowired
	private RoleService roleService;
	@Autowired
	private ResourceService resourceService;

	/**
	 * Shiro登录认证(原理：用户提交 用户名和密码 --- shiro 封装令牌 ---- realm 通过用户名将密码查询返回 ----
	 * shiro 自动去比较查询出密码和用户输入密码是否一致---- 进行登陆控制 )
	 */
	@Override
	protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authcToken)
			throws AuthenticationException {
		LOGGER.info("Shiro开始登录认证");
		UsernamePasswordToken token = (UsernamePasswordToken) authcToken;
		User user = userService.findUserByLoginName(token.getUsername());
		// 账号不存在
		if (user == null) {
			return null;
		}
		// 账号未启用
		if (user.getStatus() == 1) {
			return null;
		}
		List<Role> roleList = roleService.findRolesByUserId(user.getId());
		ShiroUser shiroUser = new ShiroUser(user.getId(), user.getLoginName(), user.getAccountName(), roleList);
		// 认证缓存信息
		return new SimpleAuthenticationInfo(shiroUser, user.getPassword().toCharArray(), getName());

	}

	/**
	 * 授权查询回调函数, 进行鉴权但缓存中无用户的授权信息时调用.
	 */
	@Override
	protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {

		ShiroUser shiroUser = (ShiroUser) principals.getPrimaryPrincipal();
		List<Role> roleList = shiroUser.getRoleList();
		/**
		 * 简单的做法
		 */
		// Set<String> urlSet = Sets.newHashSet();
		// for (Long roleId : roleList) {
		// List<Map<Long, String>> roleResourceList = roleService
		// .findRoleResourceListByRoleId(roleId);
		// if (roleResourceList != null) {
		// for (Map<Long, String> map : roleResourceList) {
		// if (StringUtils.isNoneBlank(map.get("url"))) {
		// urlSet.add(map.get("url"));
		// }
		// }
		// }
		// }
		// SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
		// info.addStringPermissions(urlSet);

		// 把principals放session中 key=userId value=principals
		SecurityUtils.getSubject().getSession().setAttribute(String.valueOf(shiroUser.getId()),
				SecurityUtils.getSubject().getPrincipals());

		SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
		// 赋予角色
		for (Role role : roleList) {
			info.addRole(role.getName());
		}
		// 赋予权限
		List<Resource> resources = resourceService.findResourceByUserId(shiroUser.getId());
		for (Resource resource : resources) {
			if (StringUtils.isNotBlank(resource.getPermCode())) {
				info.addStringPermission(resource.getPermCode());
			}
		}
		return info;
	}
}
